///////////////////////////////////////////////////////////////////////////
//
//         InfiniBand FLIT (Credit) Level OMNet++ Simulation Model
//
// Copyright (c) 2004-2013 Mellanox Technologies, Ltd. All rights reserved.
// This software is available to you under the terms of the GNU
// General Public License (GPL) Version 2, available from the file
// COPYING in the main directory of this source tree.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////
package src;
import inet.node.inet.INetworkNode;

module SwitchPort
{
    parameters:
        int numSwitchPorts;

        @display("bgb=249,215");
    gates:
        inout port;				// port to outside the switch
        inout sw_port[];		// inner switch port (between SwitchPorts)
        inout sw_sent_port[];	// inner sent msgs ports

    submodules:
        obuf: IBOutBuf 
        {
            parameters:
                isHcaOBuf = 0;
                @display("i=block/boundedqueue;p=76,80");
        }

        ibuf: IBInBuf 
        {
            parameters:
                isHcaIBuf = 0;
                numPorts = numSwitchPorts;
                @display("i=block/subqueue;p=191,80");
            gates:
                out[numSwitchPorts];
                sent[numSwitchPorts];
        }

        vlarb: IBVLArb 
        {
            parameters:
                isHcaArbiter = 0;
                numPorts = numSwitchPorts;
                @display("p=191,156;i=block/dispatch");
            gates:
                in[numSwitchPorts];
                sent[numSwitchPorts];
        }

    connections:
        obuf.out --> port$o;
        port$i --> ibuf.in;
        for i=0..numSwitchPorts-1 
        {
            vlarb.sent[i] --> sw_sent_port$o[i];
            sw_sent_port$i[i] --> ibuf.sent[i];
            ibuf.out[i] --> sw_port$o[i];
            sw_port$i[i] --> vlarb.in[i];
        }

        ibuf.rxCred --> obuf.rxCred;
        ibuf.txCred --> vlarb.txCred;
        vlarb.out --> obuf.in;
        obuf.free --> vlarb.free;
}

module IBSwitch
{
    parameters:
    	@networknode;
        @dataplane;
        @controlplane_sdn;

        // the following variables are only used in a cross-connected network
        int cross_connected_upperlevel_numswitch = default(0);
        int total_level_switch = default (0);

        int switch_index = default(0); 
        bool is_cross_connected = default(false); // true indicates the current switch is cross_connected to it's upper level switch
        int numSwitchPorts;     // Total num of switch ports for each switch

        double ISWDelay @unit(ns); // Delay brought by IBUF in SWitch
        double VSWDelay @unit(ns); // Delay in ns brought by IBUF in Switch
	    string pktFwdType;         // The type of the packet forwarding engine to use
        @display("i=abstract/router");
    gates:
        inout port[];
        inout central_controller_port;

    submodules:
        pktfwd : < pktFwdType > like PktFwd_Ifc 
        {
            parameters: 
                numPorts = numSwitchPorts;
                is_cross_connected = is_cross_connected;
                switch_index = switch_index;
            	cross_connected_upperlevel_numswitch = cross_connected_upperlevel_numswitch;
                total_level_switch = total_level_switch;
        }
        
        subport[numSwitchPorts]: SwitchPort 
        {
            parameters:
                numSwitchPorts = numSwitchPorts;
                @display("p=90,44;b=48,32");
            gates:
                sw_port[numSwitchPorts];
                sw_sent_port[numSwitchPorts];
        }

    connections allowunconnected:
        for p=0..numSwitchPorts-1 
        {
            port[p] <--> subport[p].port;

            // Loopback for inner switch ports in according ports array.
            subport[p].sw_port$o[p] --> subport[p].sw_port$i[p];
            subport[p].sw_sent_port$o[p] --> subport[p].sw_sent_port$i[p];
        }

        for p=0..numSwitchPorts-1, for i=p+1..numSwitchPorts-1 
        {
            subport[p].sw_port[i] <--> subport[i].sw_port[p];
            subport[p].sw_sent_port[i] <--> subport[i].sw_sent_port[p];
        }
        
        central_controller_port <--> pktfwd.pktfwd_port;

}